﻿using Microsoft.Practices.Unity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Tippelde.Services.Dtos;
using Tippelde.Services.Groups;
using Tippelde.Web.App_Start;

namespace Tippelde.Web.Helpers
{
    public class CacheManager
    {
        private static CacheManager _current;
        private static object _syncRoot = new object();
        private static DateTime _lastChange;
        private readonly IGroupManager _groupManager;

        private CacheManager()
        {
            _groupManager = UnityConfig.GetConfiguredContainer().Resolve<IGroupManager>();
            _lastChange = DateTime.Now;
        }

        public static CacheManager Current
        {
            get
            {
                if (_current == null)
                {
                    lock (_syncRoot)
                    {
                        if (_current == null)
                        {
                            _current = new CacheManager();
                        }
                    }
                }
                return _current;
            }
        }

        public void Init()
        {
            var groups = _groupManager.GetAllGroupHeaders();
            HttpContext.Current.Cache.Add("groups", groups, null, System.Web.Caching.Cache.NoAbsoluteExpiration, new TimeSpan(1, 0, 0), System.Web.Caching.CacheItemPriority.Normal, null);
        }

        public IEnumerable<GroupHeaderData> GetAllGroups()
        {
            if (!HttpContext.Current.User.Identity.IsAuthenticated)
                return null;
            var groups = HttpContext.Current.Cache["groups"] as IEnumerable<GroupHeaderData>;
            if (groups == null)
            {
                groups = _groupManager.GetAllGroupHeaders();
                HttpContext.Current.Cache.Add("groups", groups, null, System.Web.Caching.Cache.NoAbsoluteExpiration, new TimeSpan(1, 0, 0), System.Web.Caching.CacheItemPriority.Normal, null);
            }
            return groups;
        }

        public List<GroupHeaderData> GetGroupsForUser()
        {
            if (!HttpContext.Current.User.Identity.IsAuthenticated)
                return null;
            var lastChange = HttpContext.Current.Session["lastchange"] as DateTime?; 
            var allGroups = GetAllGroups();
            var userGroupIds = HttpContext.Current.Session["usergroupids"] as List<int>;
            if (!lastChange.HasValue || lastChange.Value < _lastChange || userGroupIds == null)
            {
                InvalidateUserGroups();
                userGroupIds = _groupManager.GetGroupIdsForUser(HttpContext.Current.User.Identity.Name);
                HttpContext.Current.Session["usergroupids"] = userGroupIds;
                HttpContext.Current.Session["editorgroupids"] = _groupManager.GetGroupIdsForEditor(HttpContext.Current.User.Identity.Name);
                HttpContext.Current.Session["lastchange"] = DateTime.Now;
            }

            return allGroups.Where(g => userGroupIds.Contains(g.Id)).ToList();
        }

        public List<GroupHeaderData> GetGroupsForEditor()
        {
            if (!HttpContext.Current.User.Identity.IsAuthenticated)
                return null;
            var lastChange = HttpContext.Current.Session["lastchange"] as DateTime?;
            var allGroups = GetAllGroups();
            var editorGroupIds = HttpContext.Current.Session["editorgroupids"] as List<int>;
            if (!lastChange.HasValue || lastChange.Value < _lastChange || editorGroupIds == null)
            {
                InvalidateUserGroups();
                var userGroupIds = _groupManager.GetGroupIdsForUser(HttpContext.Current.User.Identity.Name);
                HttpContext.Current.Session["usergroupids"] = userGroupIds;
                editorGroupIds = _groupManager.GetGroupIdsForEditor(HttpContext.Current.User.Identity.Name);
                HttpContext.Current.Session["editorgroupids"] = editorGroupIds;
                HttpContext.Current.Session["lastchange"] = DateTime.Now;
            }

            return allGroups.Where(g => editorGroupIds.Contains(g.Id)).ToList();
        }

        public List<int> GetGroupIdsForUser()
        {
            if (!HttpContext.Current.User.Identity.IsAuthenticated)
                return null;
            var lastChange = HttpContext.Current.Session["lastchange"] as DateTime?; 
            var userGroupIds = HttpContext.Current.Session["usergroupids"] as List<int>;
            if (!lastChange.HasValue || lastChange.Value < _lastChange || userGroupIds == null)
            {
                InvalidateUserGroups();
                userGroupIds = _groupManager.GetGroupIdsForUser(HttpContext.Current.User.Identity.Name);
                HttpContext.Current.Session["usergroupids"] = userGroupIds;
                var editorGroupIds = _groupManager.GetGroupIdsForEditor(HttpContext.Current.User.Identity.Name);
                HttpContext.Current.Session["editorgroupids"] = editorGroupIds;
                HttpContext.Current.Session["lastchange"] = DateTime.Now;
            }
            return userGroupIds;
        }

        public List<int> GetGroupIdsForEditor()
        {
            if (!HttpContext.Current.User.Identity.IsAuthenticated)
                return null;
            var lastChange = HttpContext.Current.Session["lastchange"] as DateTime?;
            var editorGroupIds = HttpContext.Current.Session["editorgroupids"] as List<int>;
            if (!lastChange.HasValue || lastChange.Value < _lastChange || editorGroupIds == null)
            {
                InvalidateUserGroups();
                var userGroupIds = _groupManager.GetGroupIdsForUser(HttpContext.Current.User.Identity.Name);
                HttpContext.Current.Session["usergroupids"] = userGroupIds;
                editorGroupIds = _groupManager.GetGroupIdsForEditor(HttpContext.Current.User.Identity.Name);
                HttpContext.Current.Session["editorgroupids"] = editorGroupIds;
                HttpContext.Current.Session["lastchange"] = DateTime.Now;
            }
            return editorGroupIds;
        }

        public bool UserHasAnyEditorRights()
        {
            if (!HttpContext.Current.User.Identity.IsAuthenticated)
                return false;
            var lastChange = HttpContext.Current.Session["lastchange"] as DateTime?;
            var userGroupIds = HttpContext.Current.Session["usergroupids"] as List<int>;
            var editorGroupIds = HttpContext.Current.Session["editorgroupids"] as List<int>;
            if (!lastChange.HasValue || lastChange.Value < _lastChange || !lastChange.HasValue || lastChange.Value < _lastChange || userGroupIds == null || editorGroupIds == null)
            {
                InvalidateUserGroups();
                userGroupIds = _groupManager.GetGroupIdsForUser(HttpContext.Current.User.Identity.Name);
                HttpContext.Current.Session["usergroupids"] = userGroupIds;
                editorGroupIds = _groupManager.GetGroupIdsForEditor(HttpContext.Current.User.Identity.Name);
                HttpContext.Current.Session["editorgroupids"] = editorGroupIds;
                HttpContext.Current.Session["lastchange"] = DateTime.Now;
            }
            return userGroupIds.Count > 0 && editorGroupIds.Count > 0;
        }

        public bool UserHasAnyEditorRights(int groupId)
        {
            if (!HttpContext.Current.User.Identity.IsAuthenticated)
                return false;
            var lastChange = HttpContext.Current.Session["lastchange"] as DateTime?;
            var userGroupIds = HttpContext.Current.Session["usergroupids"] as List<int>;
            var editorGroupIds = HttpContext.Current.Session["editorgroupids"] as List<int>;
            if (!lastChange.HasValue || lastChange.Value < _lastChange || userGroupIds == null || editorGroupIds == null)
            {
                InvalidateUserGroups();
                userGroupIds = _groupManager.GetGroupIdsForUser(HttpContext.Current.User.Identity.Name);
                HttpContext.Current.Session["usergroupids"] = userGroupIds;
                editorGroupIds = _groupManager.GetGroupIdsForEditor(HttpContext.Current.User.Identity.Name);
                HttpContext.Current.Session["editorgroupids"] = editorGroupIds;
                HttpContext.Current.Session["lastchange"] = DateTime.Now;
            }
            return userGroupIds.Contains(groupId) && editorGroupIds.Contains(groupId);
        }

        public void InvalidateUserGroups()
        {
            if (!HttpContext.Current.User.Identity.IsAuthenticated)
                return;
            HttpContext.Current.Cache.Remove("groups");
            HttpContext.Current.Session.Remove("usergroupids");
            HttpContext.Current.Session.Remove("editorgroupids");
            lock (_syncRoot)
            {
                _lastChange = DateTime.Now;
            }
        }

    }
}